﻿using System;
using System.Reflection;
using UnityEditor;

namespace HK.Editor.GUIEx.Drag
{
    /// <summary>
    /// 拖拽验证
    /// </summary>
    internal class DragAndDropValidate
    {
        private static MethodInfo dragDropValidation;
        /// <summary>
        /// 拖拽参数列表
        /// <para>列表数量 : 4</para>
        /// <para>Params[0] : 引用列表</para>
        /// <para>Params[1] : 类型</para>
        /// <para>Params[2] : Property</para>
        /// <para>Params[3] : Exact Type(Unity_2017_1+)</para>
        /// </summary>
        private static object[] dragDropValidationParams;
			
        /// <summary>
        /// 追加拖拽对象
        /// </summary>
        private static MethodInfo appendDragDrop;
        /// <summary>
        /// 拖拽参数列表
        /// <para>列表数量 : 1</para>
        /// <para>Params[0] : 引用对象</para>
        /// </summary>
        private static object[] appendDragDropParams;
        
        static DragAndDropValidate() 
        {
            dragDropValidation = Type.GetType("UnityEditor.EditorGUI, UnityEditor")?
                .GetMethod("ValidateObjectFieldAssignment", BindingFlags.NonPublic | BindingFlags.Static);
            appendDragDrop = typeof(SerializedProperty)
                .GetMethod("AppendFoldoutPPtrValue", BindingFlags.NonPublic | BindingFlags.Instance);
        }

        /// <summary>
        /// 验证拖拽
        /// </summary>
        /// <param name="iReferences">引用列表</param>
        /// <param name="iProperty">Property</param>
        /// <param name="iType">类型</param>
        /// <param name="iExactType">Exact Type</param>
        /// <returns>拖拽对象</returns>
        internal static UnityEngine.Object ValidateObjectDragAndDrop(Object[] iReferences, SerializedProperty iProperty, System.Type iType, bool iExactType) 
        {

#if UNITY_2017_1_OR_NEWER
            dragDropValidationParams = GetParams(ref dragDropValidationParams, 4);
            dragDropValidationParams[0] = iReferences;
            dragDropValidationParams[1] = iType;
            dragDropValidationParams[2] = iProperty;
            dragDropValidationParams[3] = iExactType ? 1 : 0;
#else
			dragDropValidationParams = GetParams(ref dragDropValidationParams, 3);
			dragDropValidationParams[0] = iReferences;
			dragDropValidationParams[1] = iType;
			dragDropValidationParams[2] = iProperty;
#endif
            return dragDropValidation.Invoke(null, dragDropValidationParams) as UnityEngine.Object;
        }
        
        /// <summary>
        /// 追加拖拽对象
        /// </summary>
        /// <param name="iObj"></param>
        /// <param name="iList">列表</param>
        internal static void AppendDragAndDropValue(Object iObj, SerializedProperty iList) 
        {

            appendDragDropParams = GetParams(ref appendDragDropParams, 1);
            appendDragDropParams[0] = iObj;
            appendDragDrop.Invoke(iList, appendDragDropParams);
        }

        private static object[] GetParams(ref object[] iParameters, int iCount)
        {
            return iParameters ?? (iParameters = new object[iCount]);
        }
    }
}
